#pragma once

#include "Connection.hpp"
#include "Epoller.hpp"
#include <unordered_map>

class Reactor
{
    static const int size = 64;

private:
    bool IsExist(int sockfd)
    {
        auto ptr = _connections.find(sockfd);
        return ptr != _connections.end(); // 不等于就是说存在于
    }

public:
    Reactor() : _epoller(std::make_unique<Epoller>())
    {
    }
    ~Reactor() {}
    void LoopOnce(int timeout)
    {
        // epoll_wait 返回值三种情况，大于0，则是就绪的事件个数；等于0表示没有事件就绪，小于0则是
        // 错误，由于此处为ET模式并且将文件描述符设置为非阻塞，所以下于0时需要利用错误码分情况讨论
        int n = _epoller->Wait(_revs, size, timeout);
        // 遍历所有的连接，看是否有就绪的，存在就绪的sockfd 就将其派发到对应的模块中进行处理
        for (int i = 0; i < n; i++)
        {
            int sockfd = _revs[i].data.fd;
            uint32_t events = _revs[i].events;

            // 还有可能会出错，判断EPOLLHUP EPOLLERR ，统一错误处理
            // 让其进入Recver Sender 内部进行统一的错误处理
            if (events & EPOLLHUP)
            {
                events = (EPOLLIN & EPOLLOUT);
            }
            if (events & EPOLLOUT)
            {
                events = (EPOLLIN & EPOLLOUT);
            }

            // 判断是哪些事件就绪了
            if (events & EPOLLIN)
            {
                // 读事件就绪
                //  _revs[i].second->Recver();
                _connections[sockfd]->Recver();
            }
            // 写事件就绪
            if (events & EPOLLOUT)
            {
                _connections[sockfd]->Sender();
            }
        }
    }
    // 作为服务器端
    void Dispatcher()
    {
        // 循环
        int timeout = 1000;
        while (true)
        {
            LoopOnce(timeout);
        }
    }
    // 增加、修改、删除连接
    void AddConnection(std::shared_ptr<Connection> &conn)
    {
        // 先判断这个sockfd 是否已经存在_connections 中
        if (IsExist(conn->Sockfd()))
            return; // 存在就不再添加

        // 回指
        conn->SetOwner(this);

        _connections.insert(std::make_pair(conn->Sockfd(), conn));
        // 将sockfd 所关心的事件设置进epoll 内核中
        _epoller->AddEvent(conn->Sockfd(), conn->Events());
    }

    void DelConnection(int sockfd)
    {
        //代码的鲁棒性
        if(!IsExist(sockfd)) return;

        //从epoll中移除关心
        _epoller->DelEvent(sockfd);

        //从_connections 中移除
        _connections.erase(sockfd);

        //关闭文件描述符
        close(sockfd);

        LOG(LogLevel::DEBUG) << "remove conn" << sockfd << "from reactor success";
    }

    void EnableReadWrite(int sockfd , bool enableread , bool enablewrite)
    {
        if(!IsExist(sockfd)) return;

        //先修改哈希表中的，再修改内核
        uint32_t events = (enableread ? EPOLLIN: 0) | (enablewrite?EPOLLOUT : 0) | EPOLLET;
        _connections[sockfd]->SetEvents(events);

        _epoller->ModEvent(sockfd, events);
    }

private:
    // 管理所有连接的结构
    // 将连接IO的等待全部交给epoll处理
    std::unordered_map<int, std::shared_ptr<Connection>> _connections;
    std::unique_ptr<Epoller> _epoller;

    // 存放就绪的文件描述符数组
    struct epoll_event _revs[size];
};